package jwt

import (
	"context"
	"fmt"
	"net/http"

	"time"

	"gitee.com/klein-x/biz/api"
	"github.com/cloudwego/hertz/pkg/app"
	"github.com/cloudwego/hertz/pkg/common/hlog"
	"github.com/cloudwego/hertz/pkg/common/utils"
	hertzJwt "github.com/hertz-contrib/jwt"
)

var (
	AccessJwtMiddleware    *hertzJwt.HertzJWTMiddleware
	RefreshJwtMiddleware   *hertzJwt.HertzJWTMiddleware
	MaxRefreshTokenTimeout time.Duration = time.Hour * 24 * 30
	RefreshTokenTimeout    time.Duration = time.Hour * 24 * 7
	AccessTokenTimeout     time.Duration = time.Hour * 6
)

func Init() error {
	if err := InitRefreshJwtMiddleware(); err != nil {
		return err
	}
	if err := InitAccessJwtMiddleware(); err != nil {
		return err
	}
	return nil
}

/*
RefreshToken负责处理登录 刷新AccessToken功能 不提供自刷新功能 到期自动失效
AccessToken负责处理业务验证, 不提供自刷新功能，不提供自动生成功能， 到期自动失效
*/

func InitRefreshJwtMiddleware() error {
	JwtMiddleware, err := hertzJwt.New(&hertzJwt.HertzJWTMiddleware{
		Realm:                       "klein-x Refresh token",
		SigningAlgorithm:            "RS512",
		Timeout:                     RefreshTokenTimeout,
		MaxRefresh:                  MaxRefreshTokenTimeout,
		TokenLookup:                 "header: token",
		TokenHeadName:               "",
		WithoutDefaultTokenHeadName: true,

		Authenticator:         OnRefreshAuthenticator,
		PayloadFunc:           OnRefreshPayload,
		LoginResponse:         OnRefreshLoginResponse,
		HTTPStatusMessageFunc: OnHTTPStatusMessageFunc,
		Unauthorized:          OnUnauthorized,
		//
		IdentityKey:       "accessToken",
		IdentityHandler:   OnRefreshIdentityHandler,
		SendCookie:        false,
		SecureCookie:      false,
		CookieHTTPOnly:    false,
		SendAuthorization: false,
		PubKeyFile:        "./key/refresh_public.pem",
		PrivKeyFile:       "./key/refresh_private.pem",
	})
	JwtMiddleware.TokenHeadName = ""
	if err != nil {
		return fmt.Errorf("初始化Refresh Jwt Middleware失败,%v", err)
	}
	RefreshJwtMiddleware = JwtMiddleware
	return nil
}

func InitAccessJwtMiddleware() error {
	JwtMiddleware, err := hertzJwt.New(&hertzJwt.HertzJWTMiddleware{
		Realm:            "klein-x access token",
		SigningAlgorithm: "RS512",
		//Key:                         []byte(""),
		//PriKeyFunc:                  OnPriKeyFunc,
		//KeyFunc:                     OnAccessKeyFunc,
		Timeout:                     AccessTokenTimeout,
		MaxRefresh:                  RefreshTokenTimeout,
		TokenLookup:                 "header: token",
		TokenHeadName:               "",
		WithoutDefaultTokenHeadName: true,
		Authenticator:               OnAccessAuthenticator,
		PayloadFunc:                 OnAccessPayload,
		LoginResponse:               OnAccessLoginResponse,
		HTTPStatusMessageFunc:       OnHTTPStatusMessageFunc,
		Unauthorized:                OnUnauthorized,

		IdentityKey:       "id",
		IdentityHandler:   OnAccessIdentityHandler,
		SendCookie:        false,
		SecureCookie:      false,
		CookieHTTPOnly:    false,
		SendAuthorization: false,
		PubKeyFile:        "./key/access_public.pem",
		PrivKeyFile:       "./key/access_private.pem",
	})
	JwtMiddleware.TokenHeadName = ""
	if err != nil {
		return fmt.Errorf("初始化Access Jwt Middleware失败,%v", err)
	}
	AccessJwtMiddleware = JwtMiddleware
	return nil
}

// Set the identity handler function
func OnAccessIdentityHandler(ctx context.Context, c *app.RequestContext) interface{} {
	if data, ok := c.Get("JWT_PAYLOAD"); ok {
		if m, ok := data.(hertzJwt.MapClaims); ok {
			return m["id"]
		}
		hlog.Infof("IdentityHandler 转换 hertzJwt.MapClaims失败,data:%v", data)
	}
	hlog.Info("IdentityHandler 获取 JWT_PAYLOAD失败")
	return nil
}

// 登录信息设置
func OnAccessAuthenticator(ctx context.Context, c *app.RequestContext) (interface{}, error) {
	if data, ok := c.Get("data"); ok {
		return data, nil
	}
	return nil, fmt.Errorf("access验证信息错误")
}

// token添加状态信息
func OnAccessPayload(data interface{}) hertzJwt.MapClaims {
	return hertzJwt.MapClaims{
		"id": data, //data中目前还没有内容
	}
}

// 返回登录成功的信息
func OnAccessLoginResponse(ctx context.Context, c *app.RequestContext, code int, token string, expire time.Time) {
	c.Set("accessCode", code)
	c.Set("accessToken", token)
	c.Set("accessExpire", expire)
}

// *****************************Refresh Function*******************************************************
// 密钥生成函数
// func OnRefreshKeyFunc(token *jwt.Token) (interface{}, error) {
// 	// if rsaRefreshPriKey == nil {
// 	// 	// 生成RSA密钥对
// 	// 	privateKey, err := rsa.GenerateKey(rand.Reader, 4096) // 4096位密钥
// 	// 	if err != nil {
// 	// 		panic(err)
// 	// 	}
// 	// 	rsaRefreshPriKey = privateKey
// 	// }
// 	// return rsaRefreshPriKey, nil
// 	if len(refreshKey) == 0 {
// 		refreshKey := make([]byte, 64) // HS512使用64字节的密钥
// 		rand.Read(refreshKey)
// 		hlog.Info(refreshKey)
// 	}
// 	return refreshKey, nil
// }

type refreshData struct {
	ctx  context.Context
	c    *app.RequestContext
	data interface{}
}

// 登录信息设置
func OnRefreshAuthenticator(ctx context.Context, c *app.RequestContext) (interface{}, error) {
	// 调用api的登录接口,获取返回的数据
	data, err := api.Login(ctx, c)
	if err != nil {
		return nil, err
	}
	return &refreshData{ctx, c, data}, nil
}

// token添加状态信息
func OnRefreshPayload(data interface{}) hertzJwt.MapClaims {
	hlog.Info("enter OnRefreshPayload")

	if value, ok := data.(*refreshData); ok {
		hlog.Info("数据解析成功")
		// 1. 设置传递给accessJwt的登录数据
		value.c.Set("data", value.data)
		// 2. 生成access token
		AccessJwtMiddleware.LoginHandler(value.ctx, value.c)

		// 3. 获取accessJwt的返回值
		if accessCode := value.c.GetInt("accessCode"); accessCode == http.StatusOK {
			return hertzJwt.MapClaims{
				// "accessToken": value.c.GetString("accessToken"),
			}
		}
	}
	return hertzJwt.MapClaims{}
}

// 返回登录成功的信息
func OnRefreshLoginResponse(ctx context.Context, c *app.RequestContext, code int, token string, expire time.Time) {
	c.JSON(http.StatusOK, utils.H{
		"code":          code,
		"refreshToken":  token,
		"refreshExpire": expire.Format(time.RFC3339),
		"accessToken":   c.GetString("accessToken"),
		"accessExpire":  c.GetTime("accessExpire").Format(time.RFC3339),
		"message":       "success",
	})
}

// *****************************nomal Function*******************************************************
func OnHTTPStatusMessageFunc(e error, ctx context.Context, c *app.RequestContext) string {
	hlog.CtxErrorf(ctx, "klein-x验证失败= %+v", e.Error())
	return e.Error()
}

// 自定义登录失败的响应函数
func OnUnauthorized(ctx context.Context, c *app.RequestContext, code int, message string) {
	errcode, isExist := c.Get("code")
	if !isExist {
		errcode = code
	}

	c.JSON(http.StatusInternalServerError, utils.H{
		"errcode": errcode,
		"message": message,
	})
	c.Abort()
}

func OnRefreshIdentityHandler(ctx context.Context, c *app.RequestContext) interface{} {
	if data, ok := c.Get("JWT_PAYLOAD"); ok {
		if m, ok := data.(hertzJwt.MapClaims); ok {
			return m["accesstoken"]
		}
		hlog.Infof("IdentityHandler 转换 hertzJwt.MapClaims失败,data:%v", data)
	}
	hlog.Info("IdentityHandler 获取 JWT_PAYLOAD失败")
	return nil
}

func Refresh(ctx context.Context, c *app.RequestContext) {
	accessToken, err := api.Refresh(ctx, c)
	if err != nil {
		c.JSON(http.StatusInternalServerError, utils.H{
			"message": err.Error(),
		})
		return
	}
	c.Request.Header.Set("token", accessToken)
	hlog.Infof("%s", c.GetHeader("token"))
	newToken, newExpire, err := AccessJwtMiddleware.RefreshToken(ctx, c)
	if err != nil {
		c.JSON(http.StatusInternalServerError, utils.H{
			"message": err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, utils.H{
		"code":         http.StatusOK,
		"accessToken":  newToken,
		"accessExpire": newExpire.Format(time.RFC3339),
		"message":      "success",
	})
}
